package com.x.intercept;

import com.x.model.BaseModel;
import lombok.extern.slf4j.Slf4j;
import net.sf.jsqlparser.expression.Expression;
import net.sf.jsqlparser.expression.JdbcParameter;
import net.sf.jsqlparser.expression.operators.relational.ExpressionList;
import net.sf.jsqlparser.parser.CCJSqlParserUtil;
import net.sf.jsqlparser.schema.Column;
import net.sf.jsqlparser.schema.Table;
import net.sf.jsqlparser.statement.Statement;
import net.sf.jsqlparser.statement.insert.Insert;
import net.sf.jsqlparser.statement.update.Update;
import net.sf.jsqlparser.statement.update.UpdateSet;
import org.apache.ibatis.executor.parameter.ParameterHandler;
import org.apache.ibatis.executor.statement.StatementHandler;
import org.apache.ibatis.mapping.BoundSql;
import org.apache.ibatis.mapping.MappedStatement;
import org.apache.ibatis.mapping.ParameterMapping;
import org.apache.ibatis.mapping.SqlCommandType;
import org.apache.ibatis.plugin.*;
import org.apache.ibatis.reflection.MetaObject;
import org.apache.ibatis.reflection.SystemMetaObject;
import org.springframework.stereotype.Component;

import javax.print.DocFlavor;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.util.ArrayList;
import java.util.List;
import java.util.Properties;
import java.util.stream.Collectors;

@Component
@Slf4j
// F5 走到下一个断点
// F10 下一步
// F11 进入方法内部
@Intercepts(@Signature(type= StatementHandler.class,method="prepare", args = {Connection.class,Integer.class}))
public class StatementPlugin  implements Interceptor {
private static  final  String  LAST_UPDATE_BY = "lastUpdateBy";
    @Override
    public Object intercept(Invocation invocation) throws Throwable {
        StatementHandler  statementHandler =  (StatementHandler)  invocation.getTarget();
        MetaObject metaObject = SystemMetaObject.forObject(statementHandler);
        MappedStatement ms = (MappedStatement)metaObject.getValue("delegate.mappedStatement");
        BoundSql boundSql = statementHandler.getBoundSql();
        Object parameterObject = boundSql.getParameterObject();
        if(parameterObject instanceof  BaseModel){
         //增强
            String sql = boundSql.getSql();
            List<ParameterMapping> parameterMappings = boundSql.getParameterMappings();
            SqlCommandType commandType = ms.getSqlCommandType();

            if(commandType == SqlCommandType.INSERT ){
                Insert insert = (Insert)CCJSqlParserUtil.parse(sql);
                //添加列字段
                insert.addColumns(new Column(LAST_UPDATE_BY));
                //添加一个占位符
                ExpressionList itemsList = insert.getItemsList(ExpressionList.class);
                itemsList.getExpressions().add(new JdbcParameter());
                //添加映射关系
                List<ParameterMapping> collect = parameterMappings.stream().filter(p -> p.getProperty().equals(LAST_UPDATE_BY)).collect(Collectors.toList());
                if(collect.size() == 0){
                    parameterMappings.add(new ParameterMapping.Builder(ms.getConfiguration(),LAST_UPDATE_BY,String.class).build());
                }
                metaObject.setValue("delegate.boundSql.sql",insert.toString());
            }
            else if(commandType == SqlCommandType.UPDATE){
                Update update = (Update)CCJSqlParserUtil.parse(sql);
                //添加列字段  同时 添加一个占位符
                update.getUpdateSets().add(new UpdateSet(new Column(LAST_UPDATE_BY),new JdbcParameter()));
                //添加映射关系
                parameterMappings.add(
                        parameterMappings.size()-1,
                        new ParameterMapping.Builder(ms.getConfiguration(),LAST_UPDATE_BY,String.class).build()
                );
                metaObject.setValue("delegate.boundSql.sql",update.toString());

            }

            String mm ="";
        }


        return invocation.proceed();
    }

    @Override
    public Object plugin(Object target) {
        return Interceptor.super.plugin(target);
    }

    @Override
    public void setProperties(Properties properties) {
        Interceptor.super.setProperties(properties);
    }
}